/*:
 * @plugindesc 復活技能目標與多技能目標
 * @author 小c
 *
 * @param Other Target Animation
 * @text 副目標技能動畫
 * @type boolean
 * @on 播放
 * @off 不播放
 * @desc 是否播放副目標的技能動畫
 * @default true
 *
 * @param Default Other Target Damage Rate
 * @text 濺射比率
 * @desc 濺射副目標傷害比率
 * @default 0.8
 * 
 * @help
 * 本插件實現的功能
 * 1. 使得復活技能物品允許對存活隊友使用來恢復HP
 * 物品/技能標籤：<For Dead Member>
 * 使該技能對我方存活及死亡目標都可以生效。
 * 使用該標籤的物品技能，作用範圍應選擇【我方單體】或【我方全體】。
 *
 * 允許復活技能通過傷害公式進行回血。
 * 物品/技能標籤<Revive Target> 執行傷害公式前復甦目標以便執行恢復。
 *
 * 2. 定義濺射技能物品，該技能物品擁有額外目標，使技能物品對多個額外目標
 * 同時生效。
 * 物品/技能標籤
 * <Target Count: x> 定義該技能的總目標數為x
 * 即<Target Count: 2>表示「秒2」，對主目標及額外【1個】目標生效。
 * <Play Secondary Target Animation: ON / OFF>
 * 是否對副目標播放技能動畫，未設定時以插件參數為準。
 * <Order Start Mode> 當物品技能濺射時，會一個個分開結算效果，類似於夢幻西
 * 遊的【鷹擊】。
 * 帶有此標籤的物品技能，YEP戰鬥序列會對每個目標正常執行。
 * 若沒有此標籤，YEP戰鬥序列對副目標無效。
 * <Other Target Damage Rate: x>
 * 濺射目標的受傷比率，沒有配置則以插件參數為準。
 */

var Imported = Imported || {};
Imported.CP_TargetControl = true;

var CP = CP || {};
CP.TargetControl = CP.TargetControl || {};
var params = PluginManager.parameters("CP_TargetControl");

CP.TargetControl.PLAY_OTHER_TARGET_ANIMATION = eval(params["Other Target Animation"]) || false;
CP.TargetControl.OTHER_TARGET_DAMAGE_RATE = Number(params["Default Other Target Damage Rate"]) || 0;

CP.TargetControl._loaded = false;
CP.TargetControl.DATABASE_LOADED = DataManager.isDatabaseLoaded;
DataManager.isDatabaseLoaded = function(){
	if(!CP.TargetControl.DATABASE_LOADED.call(this))
		return false;

	if(!CP.TargetControl._loaded){
		CP.TargetControl.loadReviveItems($dataSkills);
		CP.TargetControl.loadReviveItems($dataItems);

		CP.TargetControl.loadMutiTargetItems($dataSkills);
		CP.TargetControl.loadMutiTargetItems($dataItems);

		CP.TargetControl._loaded = true;
	}

	return true;
};

CP.TargetControl.canPlaySecondaryAnimation = function(arg){
	if(!arg)
		return false;
	var text = arg.trim().toUpperCase();
	switch(text){
		case "ON":
			return true;
		case "OFF":
			return false;
	}

	return false;
};


//讀取物品技能中的復活狀態
CP.TargetControl.loadReviveItems = function(items){
	for(var i = 1; i < items.length; i++){
		var item = items[i];
		item.forDeadMember = false;
		item.reviveTarget = false;

		if(item.meta["For Dead Member"])
			item.forDeadMember = true;
		if(item.meta["Revive Target"])
			item.reviveTarget = true;
	}
};

//讀取物品技能中的目標數
CP.TargetControl.loadMutiTargetItems = function(items){
	for(var i = 1; i < items.length; i++){
		var item = items[i];
		item.mutiTargetCount = 0;
		item.playSecondaryAnimation = CP.TargetControl.PLAY_OTHER_TARGET_ANIMATION;
		item.mutiTargetsOrderMode = false;
		item.otherTargetDamageRate = 0;

		if(item.meta["Target Count"]){
			var count = Number(item.meta["Target Count"]) || 0;
			item.mutiTargetCount = Math.floor(count - 1);
			if(item.mutiTargetCount < 0)
				item.mutiTargetCount = 0;
		}

		var playSeconary = item.meta["Play Secondary Target Animation"];
		if(playSeconary)
			item.playSecondaryAnimation = this.canPlaySecondaryAnimation(playSeconary);

		if(item.meta["Order Start Mode"])
			item.mutiTargetsOrderMode = true;

		if(item.mutiTargetCount > 0){
			item.otherTargetDamageRate = CP.TargetControl.OTHER_TARGET_DAMAGE_RATE;
			if(item.meta["Other Target Damage Rate"])
				item.otherTargetDamageRate = Number(item.meta["Other Target Damage Rate"]) || 0;
		}
	}
};

//初始化戰鬥者，判定是否為副目標
CP.TargetControl.INIT_BATTLER = Game_Battler.prototype.initialize;
Game_Battler.prototype.initialize = function() {
    CP.TargetControl.INIT_BATTLER.call(this);
    this.resetSecondaryTarget();
};

Game_Battler.prototype.resetSecondaryTarget = function(){
	this._secondaryTarget = false;
};

Game_Battler.prototype.setSecondaryTarget = function(){
	this._secondaryTarget = true;
};

Game_Battler.prototype.isSecondaryTarget = function(){
	if(!this._secondaryTarget)
		return false;

	return this._secondaryTarget;
};

//初始化隊列
CP.TargetControl.INIT_UNIT = Game_Unit.prototype.initialize;
Game_Unit.prototype.initialize = function() {
    CP.TargetControl.INIT_UNIT.call(this);
    this.resetCurAction();
};

Game_Unit.prototype.resetCurAction = function(){
	this._curAction = null;
};

Game_Unit.prototype.setCurAction = function(action){
	this._curAction = action;
};

Game_Unit.prototype.getCurAction = function(){
	if(!this._curAction)
		return null;

	return this._curAction;
};

//記錄臨時目標
CP.TargetControl.INIT_ACTION = Game_Action.prototype.initialize;
Game_Action.prototype.initialize = function(subject, forcing) {
    CP.TargetControl.INIT_ACTION.call(this, subject, forcing);
    this.resetTempTarget();
    this.resetMainTarget();
};

//判定死亡目標時所用臨時指針，用於testApply函數
Game_Action.prototype.resetTempTarget = function(){
	this._tempTarget = null;
};

Game_Action.prototype.setTempTarget = function(target){
	this._tempTarget = target;
};

Game_Action.prototype.getTempTarget = function(){
	if(!this._tempTarget)
		return null;

	return this._tempTarget;
};

Game_Action.prototype.resetMainTarget = function(){
	this._mainTarget = null;
};

Game_Action.prototype.setMainTarget = function(target){
	this._mainTarget = target;
};

Game_Action.prototype.getMainTarget = function(){
	if(!this._mainTarget)
		return null;

	return this._mainTarget;
};

//是否為順序模式
Game_Action.prototype.isTargetsOrderMode =function(){
	return this.item().mutiTargetsOrderMode;
};

//順序模式下目標計算
Game_Action.prototype.calcOrderMutiTargets = function(){
	var targets = [];
	 if(this.isForOne()){
    	var mainTarget = this.getMainTarget();
    	if(this.isMutiTargetAction(mainTarget))
    		targets = this.calcMutiTargets(mainTarget);
    	targets.unshift(mainTarget);
    }

    if(targets.length === 0)
    	targets = null;

    return targets;
};

//敵我目標計算
CP.TargetControl.ACTION_FRIEND_TARGETS = Game_Action.prototype.targetsForFriends;
Game_Action.prototype.targetsForFriends = function() {
    var unit = this.friendsUnit();
    unit.setCurAction(this);

    var targets = CP.TargetControl.ACTION_FRIEND_TARGETS.call(this);
    if(this.isForAll() && this.isForDeath())
    	targets = unit.members();

    if(this.isForOne() && this.isTargetsOrderMode()){
    	var temp = this.calcOrderMutiTargets();
    	if(temp)
    		targets = temp;
    }

    unit.resetCurAction();

    return targets;
};

CP.TargetControl.ACTION_OPPONENTS_TARGETS = Game_Action.prototype.targetsForOpponents;
Game_Action.prototype.targetsForOpponents = function() {
	var unit = this.opponentsUnit();
    unit.setCurAction(this);

    var targets = CP.TargetControl.ACTION_OPPONENTS_TARGETS.call(this);
    if(this.isForOne() && this.isTargetsOrderMode()){
    	var temp = this.calcOrderMutiTargets();
    	if(temp)
    		targets = temp;
    }

    unit.resetCurAction();

    return targets;
};

Game_Action.prototype.isForDeath = function(){
	var item = this.item();
	if(!item)
		return false;

	return item.forDeadMember;
};

Game_Action.prototype.canReviveTarget = function(){
	var item = this.item();
	if(!item)
		return false;

	return item.reviveTarget;
};

//有效目標計算
CP.TargetControl.TEST_APPLY_ACTION = Game_Action.prototype.testApply;
Game_Action.prototype.testApply = function(target) {
	this.setTempTarget(target);
    var result = CP.TargetControl.TEST_APPLY_ACTION.call(this, target);
    this.resetTempTarget();

    return result;
};

CP.TargetControl.IS_FOR_DEAD_FRIEND = Game_Action.prototype.isForDeadFriend;
Game_Action.prototype.isForDeadFriend = function() {
	var target = this.getTempTarget();

	if(target){
		if(target.isDead() && this.isForDeath())
			return true;
	}

    return CP.TargetControl.IS_FOR_DEAD_FRIEND.call(this);
};

CP.TargetControl.SMOOTH_TARGET = Game_Unit.prototype.smoothTarget;
Game_Unit.prototype.smoothTarget = function(index) {
    var target = CP.TargetControl.SMOOTH_TARGET.call(this, index);
    var action = this.getCurAction();
    
    if(action){
    	if(action.isForFriend() && action.isForDeath()){
    		if(index < 0)
    			index = 0;
    		target = this.members()[index];
    	}
    	action.setMainTarget(target);
    }

    return target;
};

Game_Action.prototype.mutiTargetCount = function(mainTarget){
	var item = this.item();

	if(!item)
		return 0;
	if(!mainTarget)
		return 0;

	var targetsCanBeSelected = this.allTargetsCanBeSelected(mainTarget);
	if(!targetsCanBeSelected)
		return 0;

	return Math.min(item.mutiTargetCount, targetsCanBeSelected.length);
};

Game_Action.prototype.isMutiTargetAction = function(mainTarget){
	return this.mutiTargetCount(mainTarget) > 0;
};

//計算濺射技能目標
Game_Action.prototype.calcMutiTargets = function(mainTarget){
	var targets = new Array();
	var unit = this.allTargetsCanBeSelected(mainTarget);

	if(!unit)
		return targets;

	var targetCount = this.mutiTargetCount(mainTarget);

	for(var i = 0; i < targetCount; i++){
		var index = Math.floor(Math.random() * unit.length);
		var randomTarget = unit[index];
		randomTarget.setSecondaryTarget();//副目標指定
		targets.push(randomTarget);
		unit.splice(index, 1);
	}

	return targets;
};

Game_Action.prototype.allTargetsCanBeSelected = function(exTarget){
	var unit = null;
	if(this.isForFriend())
		unit = this.friendsUnit().members();
	else if(this.isForOpponent())
		unit = this.opponentsUnit().aliveMembers();

	if(unit !== null && unit.length <= 0)
		return null;
	if(!unit)
		return null;

	return unit.filter(function(target){
		var test = this.testApply(target);
		if(target === exTarget)
			test = false;

		return test;
	}, this);
};

Game_Action.prototype.canPlaySecondaryAnimation = function(){
	return this.item().playSecondaryAnimation;
};

CP.TargetControl.APPLY_ACTION = Game_Action.prototype.apply;
Game_Action.prototype.apply = function(target){
	if(this.canReviveTarget())
		this.onReviveTarget(target);

    CP.TargetControl.APPLY_ACTION.call(this, target);

    if(!this.isTargetsOrderMode() && this.isMutiTargetAction(target)){
    	var mutiTargets = this.calcMutiTargets(target);
	    mutiTargets.forEach(function(otherTarget){
	    	var animation = this.item().animationId;
	    	if(animation > 0 && this.canPlaySecondaryAnimation())
	    		otherTarget.startAnimation(animation, false, 0);
	    	if(this.canReviveTarget())
	    		this.onReviveTarget(otherTarget);
	    	CP.TargetControl.APPLY_ACTION.call(this, otherTarget);

	    	var result = otherTarget.result();
	    	if(result.missed || result.evaded)
	    		otherTarget.performMiss();
	    	else if(result.hpDamage > 0)
	    		otherTarget.performDamage();

	    	var cnt = this.itemCnt(otherTarget);
	    	if(Math.random() < cnt && this._counterBattlers){
	    		if(!this._counterBattlers.contains(otherTarget))
	    			this._counterBattlers.push(otherTarget);
	    	}
	    	
	    	if(otherTarget.isDead())
	    		otherTarget.performCollapse();
	    }, this);
    }
};

Game_Action.prototype.onReviveTarget = function(target){
	if(target.isDead())
		target.removeState(target.deathStateId());
};

Game_Action.prototype.otherTargetDamageRate = function(){
	return this.item().otherTargetDamageRate;
};

CP.TargetControl.MAKE_ACTION_DAMAGE_VALUE = Game_Action.prototype.makeDamageValue;
Game_Action.prototype.makeDamageValue = function(target, critical) {
    var value = CP.TargetControl.MAKE_ACTION_DAMAGE_VALUE.call(this, target, critical);

    if(target.isSecondaryTarget() && this.isDamage() && this.otherTargetDamageRate() > 0){
    	value = Math.round(value * this.otherTargetDamageRate());
    	target.resetSecondaryTarget();
    }

    return value;
};